// TestPcap.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <stdlib.h>
#include "tchar.h"

#define _XKEYCHECK_H
#define HAVE_REMOTE
#include "pcap.h"

#pragma comment(lib, "Ws2_32.lib")

#include "..\..\..\Common\device_retriever\device_retriever.h"

#define ETHERTYPE_IP 0x0800 /* ip protocol */
#define TCP_PROTOCAL 0x0600 /* tcp protocol */

#define ETHER_ADDR_LEN 6

#pragma pack()
/*
* define struct of ethernet header , ip address , ip header and tcp header
*/
/* ethernet header */
typedef struct ether_header {
	u_char ether_shost[ETHER_ADDR_LEN]; /* source ethernet address, 8 bytes */
	u_char ether_dhost[ETHER_ADDR_LEN]; /* destination ethernet addresss, 8 bytes */
	u_short ether_type;                 /* ethernet type, 16 bytes */
}ether_header;

/* four bytes ip address */
typedef struct ip_address {
	u_char byte1;
	u_char byte2;
	u_char byte3;
	u_char byte4;
}ip_address;

/* ipv4 header */
typedef struct ip_header {
	u_char ver_ihl;         /* version and ip header length */
	u_char tos;             /* type of service */
	u_short tlen;           /* total length */
	u_short identification; /* identification */
	u_short flags_fo;       // flags and fragment offset
	u_char ttl;             /* time to live */
	u_char proto;           /* protocol */
	u_short crc;            /* header checksum */
	ip_address saddr;       /* source address */
	ip_address daddr;       /* destination address */
	u_int op_pad;           /* option and padding */
}ip_header;

/* tcp header */
typedef struct tcp_header {
	u_short th_sport;         /* source port */
	u_short th_dport;         /* destination port */
	u_int th_seq;             /* sequence number */
	u_int th_ack;             /* acknowledgement number */
	u_short th_len_resv_code; /* datagram length and reserved code */
	u_short th_window;        /* window */
	u_short th_sum;           /* checksum */
	u_short th_urp;           /* urgent pointer */
}tcp_header;

void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

int _tmain(int argc, _TCHAR* argv[])
{
	device_retriever retriever;

	std::vector<device_info *> *ptr_device_info_list = NULL;

	retriever.get_device_list(&ptr_device_info_list);

	std::vector<device_info *>::iterator iter = ptr_device_info_list->begin();
	std::vector<device_info *>::iterator itere = ptr_device_info_list->end();

	int index = 0;

	while (iter != itere)
	{
		printf("%d. %s(%s)\t\t\t\t%s\n", index ,
			(*iter)->get_friendlyname(), (*iter)->get_description(), (*iter)->get_name());

		index++;
		iter++;
	}

	scanf_s("%d", &index);

	iter = ptr_device_info_list->begin();
	iter = iter + index;

	char errbuf[PCAP_ERRBUF_SIZE];
	pcap_t *adhandle = pcap_open((*iter)->get_name(), 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf);

	if(!adhandle)
	{
		fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", (*iter)->get_name());
		return -1;
	}

	struct bpf_program fcode;

	int ret = pcap_compile(adhandle, &fcode, "ip and tcp", 1, 0);

	if (ret < 0)
		return -1;

	ret = pcap_setfilter(adhandle, &fcode);

	if (ret < 0)
		return -1;

	pcap_loop(adhandle, 0, packet_handler, NULL);

	return 0;
}

/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
	struct tm ltime;
	char timestr[16];
	time_t local_tv_sec;

	local_tv_sec = header->ts.tv_sec;
	localtime_s(&ltime, &local_tv_sec);
	strftime(timestr, sizeof timestr, "%H:%M:%S", &ltime);

	ether_header * eheader = (ether_header*)pkt_data;

	if (eheader->ether_type != htons(ETHERTYPE_IP))
		return;

	ip_header * ih = (ip_header*)(pkt_data + 14);

	if (ih->proto != htons(TCP_PROTOCAL))
		return;

	int ip_len = ntohs(ih->tlen);
	int find_http = false;
	char* ip_pkt_data = (char*)ih;
	int n = 0;
	char buffer[65536];
	int bufsize = 0;

	int len = (ih->ver_ihl & 0xf) * 4;
	tcp_header * ptr_tcp = (tcp_header*)((u_char*)ih + len);

	for (; n < ip_len; n++)
	{
		if (!find_http && ((n + 3 < ip_len && strncmp(ip_pkt_data + n, "GET", strlen("GET")) == 0)
			|| (n + 4 < ip_len && strncmp(ip_pkt_data + n, "POST", strlen("POST")) == 0)))
			find_http = true;

		if (!find_http && n + 8 < ip_len && strncmp(ip_pkt_data + n, "HTTP/1.", strlen("HTTP/1.")) == 0)
			find_http = true;

		if (find_http)
		{
			buffer[bufsize] = ip_pkt_data[n];
			bufsize++;
		}
	}

	if (find_http) {
		buffer[bufsize] = '\0';
		printf("Src: %d.%d.%d.%d:%d\t\tDes: %d.%d.%d.%d:%d\t\tSeq: %08x\tACK: %08x\n", 
			ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4, ptr_tcp->th_sport,
			ih->daddr.byte1, ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4, ptr_tcp->th_dport,
			ntohl(ptr_tcp->th_seq), ntohl(ptr_tcp->th_ack));
		printf("%s\n", buffer);
		printf("\n**********************************************\n\n");
	}

}

